package com.ikas.ai.server.module.machine.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ikas.ai.consts.MachineAndWorkConditionConst;
import com.ikas.ai.server.module.appraise.model.AppraiseResultStatistics;
import com.ikas.ai.server.module.appraise.service.AppraiseResultStatisticsService;
import com.ikas.ai.server.module.cockpit.model.dto.StartCountStatisticsDTO;
import com.ikas.ai.server.module.data.dorisDao.DorisYcDataDao;
import com.ikas.ai.server.module.data.model.doris.DorisYcData;
import com.ikas.ai.server.module.instance.dorisDao.DorisWorkFlowInstanceDao;
import com.ikas.ai.server.module.instance.dorisDao.DorisWorkInstanceStepDao;
import com.ikas.ai.server.module.instance.enums.WorkInstanceStepEnum;
import com.ikas.ai.server.module.instance.enums.WorkInstanceStepStateEnum;
import com.ikas.ai.server.module.instance.model.DorisWorkFlowInstance;
import com.ikas.ai.server.module.instance.model.DorisWorkInstanceStep;
import com.ikas.ai.server.module.machine.dao.MachineInfoDAO;
import com.ikas.ai.server.module.machine.enums.MachineInfoEnum;
import com.ikas.ai.server.module.machine.model.po.MachineInfo;
import com.ikas.ai.server.module.machine.model.vo.MachineInfoVo;
import com.ikas.ai.server.module.morningpaper.service.MorningPaperVariablesService;
import com.ikas.ai.utils.DateTimeUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 机组信息
 *
 * @author tang.xuandong
 * @version 1.0.0
 * @date 2023/5/9 16:50
 */
@Service
public class MachineInfoService extends ServiceImpl<MachineInfoDAO, MachineInfo> {
    @Autowired
    private AppraiseResultStatisticsService appraiseResultStatisticsService;
    @Autowired
    private MorningPaperVariablesService morningPaperVariablesService;
    @Autowired
    private DorisYcDataDao dorisYcDataDao;
    @Autowired
    private DorisWorkFlowInstanceDao dorisWorkFlowInstanceDao;
    @Autowired
    private DorisWorkInstanceStepDao dorisWorkInstanceStepDao;

    private static final String CURR_WC = "S";

    /**
     * 通过机组编号获取机组信息
     *
     * @param machineNo 机组编号
     * @return MachineInfo
     */
    public MachineInfo getMachineInfo(String machineNo) {
        if (StringUtils.isBlank(machineNo)) {
            return null;
        }
        LambdaQueryWrapper<MachineInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(MachineInfo::getMachineNo, machineNo);
        return getOne(wrapper);
    }

    /**
     * 通过机组编号获取机组运行时实时信息
     * 1.查询机组1最新的工况instance 取g    如果最新一条instance对应的step状态全是2，则显示step0
     * 2.根据instanceId查询step，取最新的一条作为stepName 根据startTime-currentTime作为工况运行时长
     * 3.当前工况显示nextWc字段
     * 4.instance表state为3，当前工况为s
     *
     * @param machineNo 机组编号
     * @return MachineInfoVo
     */
    public MachineInfoVo getMachineRunTimeInfo(String machineNo) {
        MachineInfoVo machineInfoVo = new MachineInfoVo();
        // 获取机组信息
        if (StringUtils.isBlank(machineNo)) {
            return machineInfoVo;
        }
        //查找当前机组最新的一条instance
        LambdaQueryChainWrapper<DorisWorkFlowInstance> instanceLambdaQueryChainWrapper = new LambdaQueryChainWrapper<>(dorisWorkFlowInstanceDao);
        List<DorisWorkFlowInstance> list = instanceLambdaQueryChainWrapper.eq(DorisWorkFlowInstance::getMachineNo, machineNo)
                .orderByDesc(DorisWorkFlowInstance::getStartTime)
                .last("limit 1").list();
        if (CollectionUtils.isEmpty(list)) {
            return machineInfoVo;
        }
        DorisWorkFlowInstance dorisWorkFlowInstance = list.get(0);
        LambdaQueryChainWrapper<DorisWorkInstanceStep> stepLambdaQueryChainWrapper = new LambdaQueryChainWrapper<>(dorisWorkInstanceStepDao);
        //根据instanceId获取step实例，获取最新的step   根据更新时间排序
        List<DorisWorkInstanceStep> workInstanceStepList = stepLambdaQueryChainWrapper.eq(DorisWorkInstanceStep::getWfInstanceId, dorisWorkFlowInstance.getId())
                .orderByDesc(DorisWorkInstanceStep::getUpdateTime).orderByDesc(DorisWorkInstanceStep::getStepId).list();
        if (dorisWorkFlowInstance.getStartTime() != null && dorisWorkFlowInstance.getStartTime() > 0) {
            machineInfoVo.setCostTime(Math.abs(System.currentTimeMillis() - dorisWorkFlowInstance.getStartTime()));
        }
        machineInfoVo.setMachineNo(dorisWorkFlowInstance.getMachineNo());
        machineInfoVo.setCurrWc(dorisWorkFlowInstance.getNextWc());
        machineInfoVo.setCurrWf(dorisWorkFlowInstance.getWfName());
        //如果状态全是失败，step0，否则展示最新的
        List<DorisWorkInstanceStep> instanceSteps = workInstanceStepList.stream().filter(i -> !WorkInstanceStepStateEnum.ERROR.getCode().equals(i.getState())).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(instanceSteps)) {
            machineInfoVo.setCurrStep(WorkInstanceStepEnum.STEP0.getName());
        } else {
            machineInfoVo.setCurrStep(workInstanceStepList.get(0).getStepName());
        }
        machineInfoVo.setStartTime(dorisWorkFlowInstance.getStartTime());
        // 获取下一个工况
        if (machineInfoVo.getStartTime() != null) {
            machineInfoVo.setStartTimeStr(DateTimeUtil.getSimpleMinTimeString(machineInfoVo.getStartTime()));
        }
        if (machineInfoVo.getCostTime() != null) {
            machineInfoVo.setCostTimeStr(DateTimeUtil.formatTimeStr(machineInfoVo.getCostTime()));
        }
//        if (WorkFlowInstanceStateEnum.ERROR.getCode().equals(dorisWorkFlowInstance.getState())) {
//            machineInfoVo.setCurrWf(null);
//            machineInfoVo.setCurrWc(CURR_WC);
//            machineInfoVo.setCurrStep(null);
//            machineInfoVo.setCostTimeStr(null);
//            machineInfoVo.setStartTimeStr(null);
//        }
        // 获取机组实时信息通过t_data
        List<String> codes = MachineInfoEnum.getCodesByMachineNo(machineNo);
        LambdaQueryWrapper<DorisYcData> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        if (StringUtils.isNotBlank(machineNo)) {
            lambdaQueryWrapper.eq(DorisYcData::getMachineNo, machineNo);
        }
        lambdaQueryWrapper.in(DorisYcData::getMeteCode, codes);
        List<DorisYcData> datas = dorisYcDataDao.selectList(lambdaQueryWrapper);
        for (
                DorisYcData data : datas) {
            MachineInfoEnum byCode = MachineInfoEnum.getByCode(data.getMeteCode());
            if (MachineInfoEnum.U01_ACTIVE_POWER.getAlias().equals(byCode.getAlias())) {
                machineInfoVo.setActivePower(data.getValue());
            } else if (MachineInfoEnum.U01_REACTIVE_POWER.getAlias().equals(byCode.getAlias())) {
                machineInfoVo.setReactivePower(data.getValue());
            } else if (MachineInfoEnum.U01_VANE_OPEN.getAlias().equals(byCode.getAlias())) {
                machineInfoVo.setVaneOpen(data.getValue());
            } else if (MachineInfoEnum.U01_SPEED.getAlias().equals(byCode.getAlias())) {
                machineInfoVo.setSpeed(data.getValue());
            }
        }
        String iMachineNo = machineInfoVo.getMachineNo();
        String machineName = transferMachineNo(iMachineNo);
        machineInfoVo.setMachineNo(machineName);
        if (CURR_WC.equals(machineInfoVo.getCurrWc())) {
            machineInfoVo.setCurrWf(null);
            machineInfoVo.setCurrStep(null);
            machineInfoVo.setCostTimeStr(null);
            machineInfoVo.setStartTimeStr(null);
        }
        return machineInfoVo;
    }


    /**
     * 通过机组编号获取机组信息
     *
     * @param machineNo 机组编号
     * @return MachineInfo
     */
    public List<MachineInfo> getMachineInfos(String machineNo) {
        List<MachineInfo> machineInfoList = new ArrayList<>();
        //查找所有机组最新的一条instance
        List<DorisWorkFlowInstance> list = dorisWorkFlowInstanceDao.selectByMachineNo();
        List<Long> idList = list.stream().map(DorisWorkFlowInstance::getId).collect(Collectors.toList());
        LambdaQueryChainWrapper<DorisWorkInstanceStep> stepLambdaQueryChainWrapper = new LambdaQueryChainWrapper<>(dorisWorkInstanceStepDao);
        //根据instanceId查询step集合
        List<DorisWorkInstanceStep> workInstanceStepList = stepLambdaQueryChainWrapper
                .in(CollectionUtils.isNotEmpty(idList), DorisWorkInstanceStep::getWfInstanceId, idList).list();
        Map<Long, List<DorisWorkInstanceStep>> map = workInstanceStepList.stream().collect(Collectors.groupingBy(DorisWorkInstanceStep::getWfInstanceId));
        list.forEach(i -> {
            MachineInfo machineInfo = new MachineInfo();
            machineInfo.setMachineNo(i.getMachineNo());
            machineInfo.setCurrWc(i.getNextWc());
            machineInfo.setCurrWf(i.getWfName());
            List<DorisWorkInstanceStep> dorisWorkInstanceSteps = map.get(i.getId());
            //如果状态全是失败，step0，否则展示最新的
            List<DorisWorkInstanceStep> instanceSteps = dorisWorkInstanceSteps.stream().filter(step -> !WorkInstanceStepStateEnum.ERROR.getCode().equals(i.getState())).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(instanceSteps)) {
                machineInfo.setCurrStep(WorkInstanceStepEnum.STEP0.getName());
            } else {
                DorisWorkInstanceStep step = dorisWorkInstanceSteps.stream().min(Comparator.comparing(DorisWorkInstanceStep::getUpdateTime).reversed()
                        .thenComparing(Comparator.comparing(DorisWorkInstanceStep::getStepId).reversed())).orElse(new DorisWorkInstanceStep());
                machineInfo.setCurrStep(step.getStepName());
            }
//            if (WorkFlowInstanceStateEnum.ERROR.getCode().equals(i.getState())) {
//                machineInfo.setCurrWf(null);
//                machineInfo.setCurrWc(CURR_WC);
//                machineInfo.setCurrStep(null);
//            }
            machineInfoList.add(machineInfo);
        });
        machineInfoList.forEach(i -> {
            String iMachineNo = i.getMachineNo();
            String machineName = transferMachineNo(iMachineNo);
            i.setMachineName(machineName);
            if (CURR_WC.equals(i.getCurrWc())) {
                i.setCurrWf(null);
                i.setCurrStep(null);
            }
        });
        return machineInfoList;
    }

    private static String transferMachineNo(String iMachineNo) {
        String machineName = null;
        switch (iMachineNo) {
            case MachineAndWorkConditionConst.MACHINE_01_NO:
                machineName = MachineAndWorkConditionConst.MACHINE_01_ALIAS;
                break;
            case MachineAndWorkConditionConst.MACHINE_02_NO:
                machineName = MachineAndWorkConditionConst.MACHINE_02_ALIAS;
                break;
            case MachineAndWorkConditionConst.MACHINE_03_NO:
                machineName = MachineAndWorkConditionConst.MACHINE_03_ALIAS;
                break;
            case MachineAndWorkConditionConst.MACHINE_04_NO:
                machineName = MachineAndWorkConditionConst.MACHINE_04_ALIAS;
                break;
            default:
        }
        return machineName;
    }

    public Map<String, Map<String, Integer>> getStateStatistics() {
        List<AppraiseResultStatistics> appraiseResultStatistics = appraiseResultStatisticsService.list();
        //根据machineNo分组
        Map<String, List<AppraiseResultStatistics>> machineMap = appraiseResultStatistics.stream().collect(Collectors.groupingBy(AppraiseResultStatistics::getMachineNo));
        Map<String, Map<String, Integer>> result = new HashMap<>(4);
        machineMap.forEach((k, v) -> {
            Map<String, Integer> scoreMap = new HashMap<>(4);
            v.forEach(a -> {
                Integer count = a.getCount();
                String scoreLevel = a.getScoreLevel();
                scoreMap.put(scoreLevel, count);
            });
            result.put(k, scoreMap);
        });
        return result;
    }

    /**
     * 获取在指定时间区间内机组运行次数
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public Map<String, Map<String, Integer>> getMachineStartStatisticsCount(String startDate, String endDate, Integer type) {
        String format = "%sS";
        StartCountStatisticsDTO startCountStatisticsDTO = morningPaperVariablesService.startCountStatistics(startDate, endDate, type);
        Map<String, Map<String, Integer>> map = new HashMap<>(4);
        Map<String, Integer> u01CountMap = new HashMap<>(4);
        u01CountMap.put(String.format(format, MachineAndWorkConditionConst.CONDITION_G), startCountStatisticsDTO.getMachineU01GStartCount());
        u01CountMap.put(String.format(format, MachineAndWorkConditionConst.CONDITION_P), startCountStatisticsDTO.getMachineU01PStartCount());
        u01CountMap.put(String.format(format, MachineAndWorkConditionConst.CONDITION_PC), startCountStatisticsDTO.getMachineU01PCStartCount());
        map.put(MachineAndWorkConditionConst.MACHINE_01_ALIAS, u01CountMap);

        Map<String, Integer> u02CountMap = new HashMap<>(4);
        u02CountMap.put(String.format(format, MachineAndWorkConditionConst.CONDITION_G), startCountStatisticsDTO.getMachineU02GStartCount());
        u02CountMap.put(String.format(format, MachineAndWorkConditionConst.CONDITION_P), startCountStatisticsDTO.getMachineU02PStartCount());
        u02CountMap.put(String.format(format, MachineAndWorkConditionConst.CONDITION_PC), startCountStatisticsDTO.getMachineU02PCStartCount());
        map.put(MachineAndWorkConditionConst.MACHINE_02_ALIAS, u02CountMap);

        Map<String, Integer> u03CountMap = new HashMap<>(4);
        u03CountMap.put(String.format(format, MachineAndWorkConditionConst.CONDITION_G), startCountStatisticsDTO.getMachineU03GStartCount());
        u03CountMap.put(String.format(format, MachineAndWorkConditionConst.CONDITION_P), startCountStatisticsDTO.getMachineU03PStartCount());
        u03CountMap.put(String.format(format, MachineAndWorkConditionConst.CONDITION_PC), startCountStatisticsDTO.getMachineU03PCStartCount());
        map.put(MachineAndWorkConditionConst.MACHINE_03_ALIAS, u03CountMap);

        Map<String, Integer> u04CountMap = new HashMap<>(4);
        u04CountMap.put(String.format(format, MachineAndWorkConditionConst.CONDITION_G), startCountStatisticsDTO.getMachineU04GStartCount());
        u04CountMap.put(String.format(format, MachineAndWorkConditionConst.CONDITION_P), startCountStatisticsDTO.getMachineU04PStartCount());
        u04CountMap.put(String.format(format, MachineAndWorkConditionConst.CONDITION_PC), startCountStatisticsDTO.getMachineU04PCStartCount());
        map.put(MachineAndWorkConditionConst.MACHINE_04_ALIAS, u04CountMap);
        return map;
    }

    /**
     * 获取在指定时间区间内机组运行时长
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public Map<String, Map<String, Double>> getMachineStartStatisticsCost(String startDate, String endDate, Integer type) {
        String format = "%sS";
        StartCountStatisticsDTO startCountStatisticsDTO = morningPaperVariablesService.startCountStatistics(startDate, endDate, type);
        Map<String, Map<String, Double>> map = new HashMap<>(4);
        Map<String, Double> u01CostMap = new HashMap<>(4);
        u01CostMap.put(String.format(format, MachineAndWorkConditionConst.CONDITION_G), startCountStatisticsDTO.getMachineU01GRuntime());
        u01CostMap.put(String.format(format, MachineAndWorkConditionConst.CONDITION_P), startCountStatisticsDTO.getMachineU01PRuntime());
        u01CostMap.put(String.format(format, MachineAndWorkConditionConst.CONDITION_PC), startCountStatisticsDTO.getMachineU01PCRuntime());
        map.put(MachineAndWorkConditionConst.MACHINE_01_ALIAS, u01CostMap);

        Map<String, Double> u02CostMap = new HashMap<>(4);
        u02CostMap.put(String.format(format, MachineAndWorkConditionConst.CONDITION_G), startCountStatisticsDTO.getMachineU02GRuntime());
        u02CostMap.put(String.format(format, MachineAndWorkConditionConst.CONDITION_P), startCountStatisticsDTO.getMachineU02PRuntime());
        u02CostMap.put(String.format(format, MachineAndWorkConditionConst.CONDITION_PC), startCountStatisticsDTO.getMachineU02PCRuntime());
        map.put(MachineAndWorkConditionConst.MACHINE_02_ALIAS, u02CostMap);

        Map<String, Double> u03CostMap = new HashMap<>(4);
        u03CostMap.put(String.format(format, MachineAndWorkConditionConst.CONDITION_G), startCountStatisticsDTO.getMachineU03GRuntime());
        u03CostMap.put(String.format(format, MachineAndWorkConditionConst.CONDITION_P), startCountStatisticsDTO.getMachineU03PRuntime());
        u03CostMap.put(String.format(format, MachineAndWorkConditionConst.CONDITION_PC), startCountStatisticsDTO.getMachineU03PCRuntime());
        map.put(MachineAndWorkConditionConst.MACHINE_03_ALIAS, u03CostMap);

        Map<String, Double> u04CostMap = new HashMap<>(4);
        u04CostMap.put(String.format(format, MachineAndWorkConditionConst.CONDITION_G), startCountStatisticsDTO.getMachineU04GRuntime());
        u04CostMap.put(String.format(format, MachineAndWorkConditionConst.CONDITION_P), startCountStatisticsDTO.getMachineU04PRuntime());
        u04CostMap.put(String.format(format, MachineAndWorkConditionConst.CONDITION_PC), startCountStatisticsDTO.getMachineU04PCRuntime());
        map.put(MachineAndWorkConditionConst.MACHINE_04_ALIAS, u04CostMap);
        return map;
    }

}
